package com.api;


import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;

import com.framework.DirectoryChooser;
import com.framework.DisplayedFrame;


public class main {

	private static File md;

	private static File f = new File("/Users/hugovicard/MIAGE/Semestre 7/Plugin Projet POO/TestProjet/bin");
	private static RepositoryT<Object> rpT = new RepositoryT<Object>(f, Object.class);
	private static JTree tree = new JTree();
	private static JPanel treePanel = new JPanel();
	private static Set<String> listePlugins = new HashSet<String>();
	private static Set<String> cartePlugins = new HashSet<String>();
	private static HashMap<String, JMenuItem> dictionnaireMenu = new HashMap<String, JMenuItem>();
	private static HashMap<String, Set<String>> dictionnaireCartes = new HashMap<String, Set<String>>();

	/**
	 * @param args
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InterruptedException {

		//Afficher la fenetre de selection de dossier
		JFrame frame = new JFrame("Explorateur de fichiers");		    
		DirectoryChooser directoryChooser = new DirectoryChooser();

		// Fermer la fenetre lors de la selection d'un dossier
		frame.addWindowListener( new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

		//Recuperer le dossier choisi
		md = directoryChooser.getSelectedDirectory();

		if (md == null) System.exit(0);
		final JPanel pluginViewer = new JPanel();
		pluginViewer.setLayout(new FlowLayout());


		//	Instancier la fenetre d'affichage general
		final JFrame window = new DisplayedFrame(treePanel);
		window.setSize(800, 500);
		window.setVisible(true);

		treePanel.setLayout( new FlowLayout() );
		JScrollPane treeScroller = new JScrollPane(treePanel);
		JScrollPane pluginScroller = new JScrollPane(pluginViewer);

		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,treeScroller, pluginScroller);
		splitPane.setBackground(Color.white);
		splitPane.setOneTouchExpandable(true);
		splitPane.setDividerLocation(250);

		//Provide minimum sizes for the two components in the split pane
		/*Dimension minimumSize = new Dimension(250, 250);
		treePanel.setMinimumSize(minimumSize);
		pluginViewer.setMinimumSize(minimumSize);*/

		window.add(splitPane);

		JMenuBar bar = new JMenuBar();
		window.setJMenuBar(bar);

		JMenu fileF = new JMenu("Fichier");
		final JMenu fileM = new JMenu("Actions");
		bar.add(fileF);
		bar.add(fileM);


		fileF.add(new AbstractAction("Ouvrir un dossier") {  
			private static final long serialVersionUID = 1L;

			@Override  
			public void actionPerformed(ActionEvent arg0) {  
				DirectoryChooser newDirectoryChooser = new DirectoryChooser();
				md = newDirectoryChooser.getSelectedDirectory();
				try {
					
					listePlugins.clear();
					dictionnaireMenu.clear();
					fileM.removeAll();
					diplaySelectedTree(window, pluginViewer);
					loadPlugins(pluginViewer, window, fileM);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 
			}

			@Override  
			public Object getValue(String arg0) {  
				if(arg0==Action.ACCELERATOR_KEY) // cannot be changed later (use putValue when possible - not anonymous)  
					return KeyStroke.getKeyStroke("control O");  
				return super.getValue(arg0);  
			}  
		});

		fileF.add(new AbstractAction("Quitter") {  
			private static final long serialVersionUID = 1L;

			@Override  
			public void actionPerformed(ActionEvent arg0) {  
				System.exit(0);
			}

			@Override  
			public Object getValue(String arg0) {  
				if(arg0==Action.ACCELERATOR_KEY) // cannot be changed later (use putValue when possible - not anonymous)  
					return KeyStroke.getKeyStroke("control Q");  
				return super.getValue(arg0);  
			}  
		});




		window.setVisible(true);

		//Parcours des differentes classes dispo (appel de tous les plugins)
		List<Class<? extends Object>> maListe;
		// Invocation du plugin d'affichage de l'arbre
		// Tant que le plugin de l'arbre n'est pas prÃ©sent, on ne fait rien d'autre que d'attendre qu'il soit prÃ©sent
		diplaySelectedTree(window, pluginViewer);

		// Chargement de tous les autres plugins
		// On boucle indéfiniment dans le cas d'ajout de nouveaux plugins à chaud
		while(true){
			loadPlugins(pluginViewer, window, fileM);
			Thread.sleep(10000);
		}
	}

	private static void loadPlugins(final JPanel pluginViewer,
			final JFrame window, JMenu fileM) throws IllegalAccessException,
			InvocationTargetException {
		List<Class<? extends Object>> maListe;
		maListe = rpT.load();
		for (final Class<?> c : maListe) {
			final Plugin classPlugin = c.getAnnotation(Plugin.class);
			if (classPlugin != null) {
				for (final Method m : c.getDeclaredMethods()) {
					final PluginMethod methodPlugin = m.getAnnotation(PluginMethod.class);
					if(methodPlugin != null) {
						if(!listePlugins.contains(methodPlugin.nom())){
							listePlugins.add(methodPlugin.nom());
							Object[] monTableau = new Object[4];
							monTableau[0] = tree;
							monTableau[1] = window;
							monTableau[2] = pluginViewer;
							monTableau[3] = md;
							if (methodPlugin.nom().equals("Icone") || methodPlugin.nom().equals("Info")) {
								m.invoke(c, monTableau);
							}
							else {
								if(methodPlugin.nomMenu() != "")
									addToMenu(fileM, c, m, methodPlugin, monTableau);
							}
						}
					}	
					else {
						final Carte cartePlugin = m.getAnnotation(Carte.class);
						if(cartePlugin != null) {
							Object[] tab = new Object[0];
							String carte = (String) m.invoke(c, tab);
							if (!cartePlugins.contains(carte)) {
								cartePlugins.add(carte);
								String extensions = carte.substring(0, carte.lastIndexOf(" - "));
								String pName = carte.substring(carte.lastIndexOf(" - ")+3, carte.length());
								if(!dictionnaireCartes.containsKey(pName)){
									Set<String> setExtensions = new HashSet<String>();
									if (extensions.length() >2) {
										String[] tabExtension = extensions.split(", ");
										for(String ext : tabExtension ){
											setExtensions.add(ext.trim());
										}
										dictionnaireCartes.put(pName, setExtensions);
									}
								}
							}
						}
					}
				}
			}
		}
	}

	private static void diplaySelectedTree(final JFrame window, final JPanel pluginViewer )
			throws IllegalAccessException, InvocationTargetException {
		List<Class<? extends Object>> maListe;
		do{
			maListe = rpT.load();
			for (final Class<?> c : maListe) {
				final PluginPrincipal classPlugin = c.getAnnotation(PluginPrincipal.class);
				if (classPlugin != null) {
					for (final Method m : c.getDeclaredMethods()) {
						final PluginMethod methodPlugin = m.getAnnotation(PluginMethod.class);
						if(methodPlugin != null) {
							listePlugins.add("Arbre");
							Object[] monTableau = new Object[1];
							monTableau[0] = md;	

							tree = (JTree) m.invoke(c, monTableau);
							tree.addTreeSelectionListener(new TreeSelectionListener()
							{
								// Appelé lorsque la valeur de la sŽlection change.
								public void valueChanged(TreeSelectionEvent event)
								{
									//désactiver tt les plugins
									for(JMenuItem j : dictionnaireMenu.values()){
										j.setEnabled(false);
									}


									// Récupérer le chemin dans l'arbre.
									TreePath selPath = tree.getSelectionPath();
									if(selPath == null) return;
									// Récupérer l'objet utilisateur correspondant.
									Object elements[] = selPath.getPath();   
									String absolutePath = new String();
									for(int i = 1; i < elements.length ; i ++){
										if(i != 1){
											absolutePath += "/";
										}
										absolutePath += elements[i];
									}

									File f = new File(md + "/" + absolutePath);
									if (f.exists()) {
										String absolutePathToLC = absolutePath.toLowerCase();				
										Iterator<String> i = dictionnaireCartes.keySet().iterator();
										while(i.hasNext()){
											String str = i.next();
											Set<String> set = dictionnaireCartes.get(str);
											for(String s : set){
												if(absolutePathToLC.endsWith(s)){
													JMenuItem j1 = dictionnaireMenu.get(str);
													j1.setEnabled(true);
												}
											}

										}
									}
								}
							});
							pluginViewer.removeAll();
							pluginViewer.repaint();
							treePanel.removeAll();
							treePanel.repaint();
							treePanel.add(tree);
							window.setVisible(true);
						}
					}
				}	
			}
		}
		while (!listePlugins.contains("Arbre"));
	}

	private static void addToMenu(JMenu fileM, final Class<?> c,
			final Method m, final PluginMethod pluginMethod,
			final Object[] monTableau) {
		
		JMenuItem j = new JMenuItem(new AbstractAction(pluginMethod.nomMenu()) {  
			private static final long serialVersionUID = 1L;

			@Override  
			public void actionPerformed(ActionEvent arg0) {  
				try {
					m.invoke(c, monTableau);
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}  
			}

			@Override  
			public Object getValue(String arg0) {  
				if(arg0==Action.ACCELERATOR_KEY) // cannot be changed later (use putValue when possible - not anonymous)  
					return KeyStroke.getKeyStroke(pluginMethod.shortcut());  
				return super.getValue(arg0);  
			}  
		});
		j.setIcon(new ImageIcon(pluginMethod.icon()));
		j.setEnabled(false);
		j.setIcon(new ImageIcon(pluginMethod.icon()));
		dictionnaireMenu.put(pluginMethod.nom(),j);
		fileM.add(j);

	}
}


